package com.ia2014.tp.portal2.ejb;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.apache.log4j.Logger;

import com.ia2014.tp.portal2.converter.ConvVO;
import com.ia2014.tp.portal2.vo.ArticuloVO;
import com.ia2014.tp.portal2.entities.Articulo;
import com.ia2014.tp.portal2.integration.rest.entities.Ranking;


@Stateless
public class AdministradorArticulosBean implements AdministradorArticulos{

	private static Logger logger = Logger.getLogger(AdministradorArticulosBean.class);
	
	@PersistenceContext(unitName = "DAO")
    EntityManager em;
	
	
	@EJB
	AdministradorConfig administradorConfig;
	
	/**
     * Formato de la fecha
     */
    private static final String FORMATO_FECHA = "yyyy/MM/dd";

    /**
     * Formateador de la fecha
     */
    private static SimpleDateFormat fechaFormater = new SimpleDateFormat(FORMATO_FECHA);
    
    
    /**
     * Default constructor. 
     */
    public AdministradorArticulosBean() {
        // TODO Auto-generated constructor stub
    }

	@Override
	public void agregarArticulo(Articulo articulo) {
		
		try{
			//Verifica si ya existe el articulo
			//No se insertan Articulos donde se duplique el Codigo y ModuloId
			if(articulo.getId() == null){
			
				ArticuloVO articuloVO = getArticulo(articulo.getCodigo(),articulo.getIdModulo(), articulo.getCategoria());
			
				if(articuloVO != null){
					//Existe el articulo. Asigna el ID
					articulo.setId(articuloVO.getId());
				}
			}
		
			if(articulo.getId() != null){
				//Actualiza el articulo
				em.merge(articulo);
			}
			else {
				//Persiste el nuevo Articulo
				em.persist(articulo);
			}
		}
		catch (PersistenceException pe){
			logger.error("Error al persistir Nuevo Articulo\n" + 
					"Codigo: " + String.valueOf(articulo.getCodigo()) + "\n" + 
					"IdModulo: " + String.valueOf(articulo.getIdModulo()) + "\n" +
					"Categoria: " + articulo.getCategoria());
			logger.error(pe.toString());
			logger.debug("Stacktrace", pe);
		}
		catch(Exception e){
			
			logger.error("Error al persistir Nuevo Articulo\n" + 
					"Codigo: " + String.valueOf(articulo.getCodigo()) + "\n" + 
					"IdModulo: " + String.valueOf(articulo.getIdModulo()) + "\n" +
					"Categoria: " + articulo.getCategoria());
			logger.error(e.toString());
			logger.debug("Stacktrace", e);

		}
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ArticuloVO> getListaArticulos() {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			Query query = em.createQuery("from Articulo");
		
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch(NoResultException re){
			logger.warn("No se obtuvieron articulos de la Base de Datos");
			
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
		}
		catch(Exception e){
			logger.error("Error al obtener la lista de Articulo");
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}
	
	
	@Override
	public ArticuloVO getArticulo(Integer codigo, Integer idModulo, String categoria) {		
		
		try {
			
			Query query = em.createQuery("from Articulo a where a.codigo = :codigo and a.idModulo = :idModulo and a.class = :categoria");
		
			query.setParameter("codigo", codigo);
			query.setParameter("idModulo", idModulo);
			query.setParameter("categoria", categoria);
			
			Articulo articulo = (Articulo) query.getSingleResult();
			
			return articulo.getVO();
		
		} catch (NoResultException e) {
		
			logger.warn("No se obtuvo el articulo con Codigo " + String.valueOf(codigo) + 
					" del Modulo " + String.valueOf(idModulo) + " dentro de la categoria " + categoria.toUpperCase());
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", e);
			
			
			return null;
			
		} catch(Exception e){
			
			logger.error("Error al tratar de obtener el articulo con Codigo " + String.valueOf(codigo) + 
					" del Modulo " + String.valueOf(idModulo) + " dentro de la categoria " + categoria.toUpperCase());
			logger.debug("Stacktrace", e);
						
			return null;
		}
		
	}
	
	@Override
	public ArticuloVO getArticuloByCodigo(Integer codigo) {		
		
		Query query = em.createQuery("from Articulo a where a.codigo = :codigo");
		
		query.setParameter("codigo", codigo);
		
		try {
			Articulo articulo = (Articulo) query.getSingleResult();
			return articulo.getVO();
		
		} catch (NoResultException e) {
		
			logger.warn("No se obtubo el articulo con codigo " + String.valueOf(codigo));
			
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", e);
			
			return null;
		} catch (Exception e) {
			
					
			logger.error("Error al tratar de obtener el articulo con codigo " + String.valueOf(codigo));
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}

	}

	@Override
	public ArticuloVO getArticuloById(Integer idArticulo) {
		try{

			Articulo articulo = this.em.find(Articulo.class, idArticulo);	
			if (articulo != null)
				return articulo.getVO();
			else
				return null;

		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvo el Articulo con ID: " + String.valueOf(idArticulo));
			
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener el Articulo con ID: " + String.valueOf(idArticulo));
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}

	@Override
	public List<ArticuloVO> getListaArticulosByCategoria(String categoria) {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			Query query = em.createQuery("from Articulo a where a.class = :categoria");
			query.setParameter("categoria", categoria);
		
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvieron Articulos de la Categoria: " + categoria);
			
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener los Articulos de la Categoria: " + categoria);
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}

	@Override
	public List<ArticuloVO> getListaArticulosByFecha(Date fechaDesde, Date fechaHasta) {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			//System.out.println("Desde: " + fechaDesde.toString());
			//System.out.println("Hasta: " + fechaHasta.toString());
			
			Query query = em.createQuery("from Articulo a where a.fecha >= :fechaDesde and a.fecha <= :fechaHasta");
			query.setParameter("fechaDesde", fechaDesde);
			query.setParameter("fechaHasta", fechaHasta);
			
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvieron Articulos cargados entre las fecha " + String.valueOf(fechaDesde) + " y " + String.valueOf(fechaHasta));
			
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener Articulos cargados entre las fecha " + String.valueOf(fechaDesde) + " y " + String.valueOf(fechaHasta));
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}
	
	@Override
	public List<ArticuloVO> getListaArticulosByPrecio(double precioDesde, double precioHasta) {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			Query query = em.createQuery("from Articulo a where a.precio >= :precioDesde and a.precio <= :precioHasta");
			query.setParameter("precioDesde", precioDesde);
			query.setParameter("precioHasta", precioHasta);
		
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvieron Articulos con precio entre $" + String.valueOf(precioDesde) + " y $" + String.valueOf(precioHasta));
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener Articulos con precio entre $" + String.valueOf(precioDesde) + " y $" + String.valueOf(precioHasta));
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}
	
	@Override
	public List<ArticuloVO> getListaArticulosByNombre(String nombre) {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			Query query = em.createQuery("from Articulo a where upper(a.nombre) like upper(:nombre)");
			query.setParameter("nombre", "%" + nombre + "%");
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvieron Articulos con el nombre " + nombre);
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener Articulos con el nombre " + nombre);
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			
			return null;
		}
	}
	
	@Override
	public List<ArticuloVO> getListaBestSellers() {
		try{
			List<Articulo> articulos = new ArrayList<Articulo>();
		
			Query query = em.createQuery("from Articulo a where a.ranking >0 and a.ranking < 20 order by p.ranking");
		
			articulos = query.getResultList();
		
			return ConvVO.getListaVoFromEntity(articulos);
		}
		catch (NoResultException re){
			
			logger.warn("No se obtuvo la lista de BestSellers");
			//if (administradorConfig.getAuditarStacktraceNoResultException())
			//	logger.debug("Stacktrace", re);
			
			return null;
			
		}
		catch(Exception e){
			logger.error("Error al obtener la lista de BestSellers");
			logger.error(e.toString());
			logger.debug("Stacktrace", e);
			return null;
		}
	}
	
	@Override
	public void actualizarListaBestSellers(List<Ranking> listaRanking) {
		Ranking rank = null;
		
		Iterator<Ranking> iter = listaRanking.iterator();
		
		while (iter.hasNext()) {
			rank = (Ranking) iter.next();
			
			Query query = em.createQuery("from Articulo a where a.codigo = :codigo");
			query.setParameter("codigo", rank.getCodigoArticulo());
			
			Articulo articulo = null;
			
			try {
				
				articulo = (Articulo) query.getSingleResult();
				articulo.setRanking(rank.getPosicion());
				
			} catch (NoResultException re) {
								
				logger.warn("No se obtuvo el articulo con codigo " + String.valueOf(rank.getCodigoArticulo()) + " para actualizar el Ranking");
				
				//if (administradorConfig.getAuditarStacktraceNoResultException())
				//	logger.debug("Stacktrace", re);
				
			} catch (Exception e) {
				logger.error("Error al tratar de obtener el articulo con codigo " + String.valueOf(rank.getCodigoArticulo())+ " para actualizar el Ranking");
				logger.error(e.toString());
				logger.debug("Stacktrace", e);
			}
			
			
			if(articulo != null) {
				try{
					
					articulo.setRanking(rank.getPosicion());
				
					em.merge(articulo);
					
				}
				catch (PersistenceException pe){
					logger.error("Error al tratar de persistir el Ranking del Articulo con codigo "  + String.valueOf(rank.getCodigoArticulo()));
					logger.error(pe.toString());
					logger.debug("Stacktrace", pe);
				}
				catch(Exception e){
					logger.error("Error al tratar de persistir el Ranking del Articulo con codigo "  + String.valueOf(rank.getCodigoArticulo()));
					logger.error(e.toString());
					logger.debug("Stacktrace", e);
				}
				
			}
		}
		
		
	}
}